<template>
  <div class="cesium-wrap">
    <div id="cesiumContainer"></div>
    <div class="distance-label" v-if="distanceLabel">
      <div class="distance-label-line" :style="{ width: distanceWidth }">{{ distanceLabel }}</div>
    </div>
    <div class="tool-box">
      <div class="tool-item" v-for="list in toolList" :key="list.code" @click="toolChange(list)">
        <SvgIcon
          :style="{ transform: `rotate(${list.code === 1 ? -northAngle : 0}deg)` }"
          :icon-class="list.icon"
        >
        </SvgIcon>
      </div>
    </div>
    <div class="lonlat">
      高度：{{ lonlat.height }} 经度：{{ lonlat.longitude }} 纬度：{{ lonlat.latitude }}
    </div>
  </div>
  <!-- 加载进度条 -->
  <Loading
    v-if="isShowLoading"
    :loading-complete="loadingComplete"
    @close="isShowLoading = false"
  />
</template>

<script setup lang="ts">
import { useSceneStore } from '@/store/scene';
import Loading from '../detail/components/loading.vue';
import { addLayer, setLayerVisible, getLayerMap, addPanelTag } from '@/service';
import { addlayerRequestIns } from '@/service/effect';
import withBase from '@jl/common/src/utils/path';
import { round } from 'lodash';

defineOptions({
  name: 'Cesium',
});

const sceneStore = useSceneStore();
const isShowLoading = ref<boolean>(true);
const loadingComplete = ref<boolean>(false);
// 比例尺
const distanceLabel = ref<string>('');
const distanceWidth = ref<string>('100%');
// 经纬度
const lonlat = ref<any>({
  longitude: 0,
  latitude: 0,
  height: 0,
});
// 指北角度
const northAngle = ref<number>(0);

const toolList = [
  { code: 1, name: '指北针', icon: 'ic_指南针' },
  { code: 2, name: '放大', icon: 'ic_+' },
  { code: 3, name: '缩小', icon: 'ic_-' },
  { code: 4, name: '全屏', icon: 'ic_全屏' },
  { code: 5, name: '默认视角', icon: 'ic_地球' },
];
const isFullScreen = ref<boolean>(false);

const defaultMapObject = {
  view: {
    longitude: 113.92878028208328,
    latitude: 30.089004097298577,
    height: 10000371.007221604,
    duration: 3,
    heading: 6.2831853071795765,
    pitch: -1.570782970133429,
    maxDistance: 10000000,
    initViewStatically: true,
  },
  layers: [
    {
      enable: true,
      index: 0,
      type: 'base',
      mapType: 'SINGLEIMAGE',
      dataSourceUrl: withBase() + '/images/globe.png',
      extent: [-180, -90, 180, 90],
    },
    {
      enable: true,
      index: 500,
      type: 'divTool',
    },
  ],
};

const init = () => {
  const { CIMUP, Cesium } = window;

  const cimInstance = CIMUP.CimEngine.instance;

  window.cimInstance = cimInstance;
  if (!sceneStore.sceneDetail) return;
  let configJson = sceneStore.sceneDetail.configJson
    ? JSON.parse(sceneStore.sceneDetail.configJson)
    : null;
  if (configJson) {
    // 处理预置场景

    if (!configJson.cimup) {
      configJson = setDefaultSceneConfig(configJson);
    }
    // 粒子特效处理、参数化特效处理
    if (configJson.cimup.mapObject.entities) {
      for (const list of configJson.layer) {
        if (['entity', 'fake_particleSystem'].includes(list.type)) {
          const actualJson = configJson.cimup.mapObject.entities.filter(
            (item: any) => item.name === list.layerName
          );
          if (actualJson.length) {
            list.json = actualJson[0];
          }
        }
      }
    }

    const layerMap = getLayerMap();
    sceneStore.layerList = configJson.layer;
    configJson.layer.forEach((item: API.Scene.ILayer) => {
      layerMap.set(item.code, item.code);
    });

    configJson = disposeEffect(configJson);
  }
  const cimInitParam: any = {
    config: {
      gisContainer: 'cesiumContainer',
      map: '谷歌',
      mapObject: configJson ? configJson.cimup.mapObject : defaultMapObject,
    },
  };
  if (configJson && configJson.cimup.options) {
    cimInitParam.config.options = configJson.cimup.options;
  }
  if (sceneStore.sceneDetail.longitude && sceneStore.sceneDetail.latitude) {
    if (cimInitParam.config.mapObject.position) {
      cimInitParam.config.mapObject.position.targetPosition = [
        Number(sceneStore.sceneDetail.longitude),
        Number(sceneStore.sceneDetail.latitude),
      ];
    } else {
      cimInitParam.config.mapObject.position = {
        targetPosition: [
          Number(sceneStore.sceneDetail.longitude),
          Number(sceneStore.sceneDetail.latitude),
        ],
      };
    }
  }

  cimInstance.init(cimInitParam);
  cimInstance.eventApi.addEventListener('set_data_complete', async () => {
    console.log('底座初始化结束');
    sceneStore.isCimupComplete = true;
    // div、entity、参数化 类型处理
    sceneStore.layerList.forEach((item: API.Scene.ILayer) => {
      if (item.type === 'div') {
        addPanelTag({
          longitude: item.attr.position[0],
          latitude: item.attr.position[1],
          height: item.attr.position[2],
          ...item,
        });
        addlayerRequestIns(item);
      } else if (['entity', 'fake_particleSystem'].includes(item.type)) {
        addLayer(item);
      }
    });
  });
  cimInstance.eventApi.addEventListener('camera_change', function () {
    const scaleObj = cimInstance.api.getSceneScale();
    if (scaleObj) {
      distanceLabel.value = scaleObj.distanceLabel;
      distanceWidth.value = scaleObj.barWidth + 'px';
    }
    // console.log('比例尺----', scaleObj);
    const cameraParam = cimInstance.api.getCameraParameter();
    // console.log(cameraParam);
    lonlat.value.longitude = round(cameraParam.longitude, 4);
    lonlat.value.latitude = round(cameraParam.latitude, 4);
    lonlat.value.height = round(cameraParam.height, 4);
    sceneStore.mapCameraHeight = round(cameraParam.height, 4);
    northAngle.value = cameraParam.heading * Cesium.Math.DEGREES_PER_RADIAN;
    // console.log('指北针---', cameraParam.heading * Cesium.Math.DEGREES_PER_RADIAN);
  });
  cimInstance.eventApi.addEventListener('scene_tile_loaded', tileLoadComplete);
};

function setDefaultSceneConfig(configJson: any) {
  configJson = {
    cimup: configJson,
    layer: [],
  };
  let isExistDivTool = false;
  for (const layer of configJson.cimup.mapObject.layers) {
    if (
      layer.type === 'base' &&
      layer.mapType === 'SINGLEIMAGE' &&
      layer.dataSourceUrl.indexOf('globe.png') > -1
    ) {
      layer.dataSourceUrl = withBase() + '/images/globe.png';
    } else if (layer.type === 'image') {
      configJson.layer.push({
        code: Math.random().toString().split('.')[1],
        show: true,
        json: layer,
        name: layer.name,
        layerName: layer.name,
        desc: '',
        type: 'imageLayer',
      });
    } else if (layer.type === 'gltfmodel') {
      configJson.layer.push({
        code: Math.random().toString().split('.')[1],
        show: true,
        json: layer,
        name: layer.name,
        layerName: layer.name,
        desc: '',
        type: 'gltfmodel',
        attr: {
          position: layer.positions[0],
          translation: [0, 0, 0],
          rotation: layer.rotation,
          scale: layer.scale,
          color: '',
        },
      });
    } else if (layer.type === 'divTool') {
      isExistDivTool = true;
    }
  }
  if (!isExistDivTool) {
    configJson.cimup.mapObject.layers.push({
      enable: true,
      index: 500,
      type: 'divTool',
    });
  }
  return configJson;
}

function toolChange(item: any) {
  const { cimInstance } = window;
  if (item.code === 1) {
    cimInstance.api.setCameraHeadNorth();
    return;
  }
  if (item.code === 2) {
    cimInstance.api.forwardCameraByScale(0.1);
    return;
  }
  if (item.code === 3) {
    cimInstance.api.forwardCameraByScale(-0.1);
    return;
  }
  if (item.code === 4) {
    isFullScreen.value = !isFullScreen.value;
    if (isFullScreen.value) {
      cimInstance.api.fullScreen(document.body);
    } else {
      cimInstance.api.exitFullscreen();
    }
    return;
  }
  if (item.code === 5) {
    cimInstance.api.flyToHome();
  }
}

function disposeEffect(configJson: any) {
  const allGltfModelName: string[] = [];
  configJson.cimup.mapObject.layers.forEach((item: any) => {
    if (item.type === 'gltfmodel') {
      allGltfModelName.push(item.name);
    }
  });
  // 对于依赖模型的特效去除
  for (let i = configJson.cimup.mapObject.layers.length - 1; i >= 0; i--) {
    if (
      configJson.cimup.mapObject.layers[i].type === 'cim_particleSystem' &&
      allGltfModelName.includes(configJson.cimup.mapObject.layers[i].owner)
    ) {
      configJson.cimup.mapObject.layers.splice(i, 1);
      continue;
    }
  }
  return configJson;
}

onMounted(() => {
  init();
});

function tileLoadComplete() {
  console.log('--地图加载完成--');
  loadingComplete.value = true;
}

watch(
  () => sceneStore.layerList,
  () => {
    const layerMap = getLayerMap();
    for (const list of sceneStore.layerList) {
      if (layerMap.get(list.code)) {
        setLayerVisible(list);
      } else {
        addLayer(list);
        layerMap.set(list.code, list.code);
      }
    }
  },
  {
    deep: true,
  }
);

watch(
  () => loadingComplete.value,
  () => {
    const { cimInstance } = window;
    if (loadingComplete.value) {
      cimInstance.eventApi.removeEventListener('scene_tile_loaded', tileLoadComplete);
    }
  }
);
</script>

<style lang="less" scoped>
.cesium-wrap,
#cesiumContainer {
  position: absolute;
  width: 100%;
  height: 100%;
}
.cesium-wrap {
  position: relative;
  overflow: hidden;
  .distance-label {
    position: absolute;
    right: 20px;
    bottom: 50px;
    display: flex;
    justify-content: center;
    align-items: flex-end;
    height: 36px;
    background: #303640;
    border-radius: 8px;
    color: #fff;
    font-size: 14px;
    padding: 7px 20px;
    &-line {
      display: flex;
      justify-content: center;
      align-items: flex-end;
      width: 100%;
      height: 8px;
      border: 1px solid #ffffff;
      border-top: none;
      line-height: 22px;
    }
  }
  .tool-box {
    position: absolute;
    top: 20px;
    right: 20px;
    .tool-item {
      display: flex;
      justify-content: center;
      align-items: center;
      width: 36px;
      height: 36px;
      background: #2a2e33;
      border-radius: 8px;
      margin-bottom: 10px;
      cursor: pointer;
      .svg-icon {
        margin-right: 0px;
        font-size: 24px;
      }
    }
  }
  .lonlat {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 30px;
    background: #222528;
    color: #e8e8e8;
    font-size: 14px;
    padding: 0 20px;
    border-top: 1px solid #000;
  }
  .whitemodel-delete-wrap {
    position: absolute;
    width: 186px;
    height: 108px;
    background: #161616;
    box-shadow: 0px 12px 48px 16px rgba(0, 0, 0, 0.03), 0px 9px 28px 0px rgba(0, 0, 0, 0.05),
      0px 6px 16px -8px rgba(0, 0, 0, 0.08);
    border-radius: 16px;
    color: #fff;
    font-size: 14px;
    padding: 20px 24px;
    .title-wrap {
      display: flex;
      align-items: center;
      margin-bottom: 12px;
      .svg-icon {
        font-size: 24px;
        margin-right: 10px;
      }
    }
    .btn-wrap {
      display: flex;
      .btn {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 65px;
        height: 32px;
        border-radius: 8px;
        border: 1px solid #0560fd;
        margin-right: 8px;
        cursor: pointer;
        &.btn-delete {
          background-color: #0560fd;
        }
        &:last-child {
          margin-right: 0px;
        }
      }
    }
  }
}
</style>
